package com.free.ext.mybatis.warpper;

import com.free.beanutils.BeanUtils;
import com.free.common.vo.PageResponseVo;
import com.free.exception.SystemException;
import com.free.exception.SystemRuntimeException;
import com.free.ext.mybatis.dao.BaseDao;
import com.free.ext.mybatis.delegate.ICommonDao;
import com.free.ext.mybatis.model.entity.PageResponseModel;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * <p>
 * 功能概述:
 * </p>
 * <p>
 * 功能详述:
 * </p>
 */
public abstract class BaseDaoWarpper<V, K, T> implements ICommonDao<V, K> {

    /*========================================================================*
     *                         Public Fields (公共属性)
     *========================================================================*/

    /*========================================================================*
     *                         Private Fields (私有属性)
     *========================================================================*/

    @Autowired
    BaseDao<T, K> baseDao;

    /*========================================================================*
     *                         Construct Me菜单thods (构造方法)
     *========================================================================*/

    /*========================================================================*
     *                         Public Methods (公有方法)
     *========================================================================*/
    @Override
    public V get(K key)
    {
        T obj = baseDao.select(key);
        return convertToView(obj);
    }


    @Override
    public V add(V entity)
    {
        T tbl = convertToTable(entity);
        baseDao.insert(tbl);
        return convertToView(tbl);
    }


    @Override
    public int delete(K key)
    {
        return baseDao.delete(key);
    }


    public int deleteByCondition(V entity){
        T tbl = convertToTable(entity);
        return baseDao.deleteByCondition(tbl);
    }

    @Override
    public int update(V entity)
    {
        T tbl = convertToTable(entity);
        return baseDao.update(tbl);
    }


    @Override
    public V selectOne(V cond)
    {
        T tbl = convertToTable(cond);
        T res = baseDao.selectOne(tbl);
        return convertToView(res);
    }


    @Override
    public int selectCount(V cond)
    {
        T tbl = convertToTable(cond);
        return baseDao.selectCount(tbl);
    }


    public int selectCountByExample(Object example)
    {
        return baseDao.selectCountByExample(example);
    }


    @Override
    public List<V> selectList(V cond, String orderBy)
    {
        T tbl = convertToTable(cond);
        List<V> res = new ArrayList<V>();
        List<T> lst = baseDao.selectList(tbl, orderBy);

        if (lst == null || lst.size() == 0)
            return res;

        lst.forEach(x -> {
            res.add(convertToView(x));
        });
        return res;
    }


    @Override
    public PageResponseVo<V> selectByPageNo(V condition, String orderBy, int pageNo, int pageSize)
    {
        T tbl = convertToTable(condition);
        PageResponseModel<T> pgModel = baseDao.selectByPageNo(tbl, orderBy, pageNo, pageSize);
        return convertToViewResponseVo(pgModel);
    }


    // 通过反射去查找会慢，要用的时候最好自己写
    public Example getConditionExample()
    {
        Example example = new Example(getTClass(2));
        return example;
    }


    @SuppressWarnings("unchecked")
    protected T convertToTable(V viewObj)
    {
        T dest = (T) getDestObject(getTClass(2));
        return convertTo(dest, viewObj);
    }


    @SuppressWarnings("unchecked")
    protected V convertToView(T tblObj)
    {
        V dest = (V) getDestObject(getTClass(0));
        return convertTo(dest, tblObj);
    }

    @SuppressWarnings("unchecked")
    protected List<T> convertToTbList(List<V> views){
        List<T> tbs = new ArrayList<>();
        if(views != null && views.size() >0){
            views.forEach(x->{
                tbs.add(convertToTable(x));
            });
        }
        return tbs;
    }

    @SuppressWarnings("unchecked")
    protected List<V> convertToViewList(List<T> tbs){
        List<V> views = new ArrayList<>();
        if(tbs != null && tbs.size() >0){
            tbs.forEach(x->{
                views.add(convertToView(x));
            });
        }
        return views;
    }

    @SuppressWarnings("unchecked")
    protected PageResponseVo<V> convertToViewResponseVo(PageResponseModel<T> orig)
    {
        PageResponseVo<V> pgVo = new PageResponseVo<V>((Class<V>) getTClass(0));
        return convertTo(pgVo, orig);
    }


    protected <Tg, Vg> PageResponseVo<Vg> convertToViewResponseVo(PageResponseModel<Tg> tblResp, Function<Tg, Vg> func)
    {
        PageResponseVo<Vg> viewResp = null;
        if (tblResp != null)
        {
            viewResp = new PageResponseVo<Vg>();
            String[] ingores = {"list"};
            BeanUtils.copyProperties(viewResp, tblResp, ingores);
            if (tblResp.getList() != null && tblResp.getList().size() > 0)
            {
                final List<Vg> list = new ArrayList<Vg>();
                tblResp.getList().forEach(x -> {
                    list.add(func.apply(x));
                });
                viewResp.setList(list);
            }
        }
        return viewResp;
    }


    private Object getDestObject(Class<?> clazz) {
        try
        {
            Object tObj = clazz.newInstance();
            return tObj;
        }
        catch (Throwable t)
        {
            throw new SystemRuntimeException("", t);
        }
    }


    public abstract void registerEnums();


    protected <T1, K1> T1 convertTo(T1 dest, K1 orig)
    {
        if (orig == null)
        {
            return null;
        }
        registerEnums();
        BeanUtils.copyProperties(dest, orig);
        return dest;
    }


    private Class<?> getTClass(int idx)
    {
        return (Class<?>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[idx];
    }
    /*========================================================================*
     *                         Private Methods (私有方法)
     *========================================================================*/
}
